﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace jvm.rtda.frame
{
    class JOperandStack
    {
        public Slot[] slots;
        public uint size;

        public JOperandStack(uint size)
        {
            slots = new Slot[size];
        }

        public void PushBoolean(bool value)
        {
            if (value)
            {
                PushInt(1);
            }
            else
            {
                PushInt(0);
            }
        }

        public void PushInt(int value)
        {
            slots[size] = new Slot();
            slots[size++].value = value;
        }

        public void PushFloat(float value)
        {
            slots[size] = new Slot();
            slots[size++].value = BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
        }

        public void PushLong(long value)
        {
            slots[size] = new Slot();
            slots[size + 1] = new Slot();
            slots[size++].value = BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
            slots[size++].value = BitConverter.ToInt32(BitConverter.GetBytes(value), 4);
        }

        public void PushDouble(double value)
        {
            slots[size] = new Slot();
            slots[size + 1] = new Slot();
            slots[size++].value = BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
            slots[size++].value = BitConverter.ToInt32(BitConverter.GetBytes(value), 4);
        }

        public void PushRef(JObject obj)
        {
            slots[size] = new Slot();
            slots[size++].reference = obj;
        }

        public void PushSlot(Slot slot)
        {
            slots[size++] = slot;
        }

        public bool PopBoolean()
        {
            return slots[--size].value == 1;
        }

        public int PopInt()
        {
            return slots[--size].value;
        }

        public float PopFloat()
        {
            return BitConverter.ToSingle(BitConverter.GetBytes(slots[--size].value), 0);
        }

        public long PopLong()
        {
            byte[] bytes = BitConverter.GetBytes(slots[size - 2].value).Concat(BitConverter.GetBytes(slots[size - 1].value)).ToArray();
            size -= 2;
            return BitConverter.ToInt64(bytes, 0);
        }

        public double PopDouble()
        {
            byte[] bytes = BitConverter.GetBytes(slots[size - 2].value).Concat(BitConverter.GetBytes(slots[size - 1].value)).ToArray();
            size -= 2;
            return BitConverter.ToDouble(bytes, 0);
        }

        public JObject PopRef()
        {
            return slots[--size].reference;
        }

        public Slot PopSlot()
        {
            return slots[--size];
        }

        public JObject GetRefFromTop(uint n)
        {
            return slots[size - n - 1].reference;
        }

        public void Clear()
        {
            size = 0;
            for (int i = 0; i < slots.Length; i++)
            {
                slots[i].reference = null;
            }
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("[JOperandStack:");
            for (uint i = 0; i < size; i++)
            {
                builder.Append(" (");
                if (slots[i].reference != null)
                {
                    builder.Append(slots[i].reference);
                }
                else
                {
                    builder.Append(slots[i].value);
                }
                builder.Append(") ");
            }
            builder.Append("]");
            return builder.ToString();
        }
    }
}
